using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Physics.Math;
using Physics.Physics;
using Physics.Collision;
using Physics.Geometry;

using CubeWars___Demolition.Services;

namespace CubeWars___Demolition.Levels
{

    /// <summary>
    /// Helps to combine the physics with the graphics.
    /// </summary>
    public class Level1 : DrawableGameComponent
    {
        protected struct physicModel
        {
            public Body body;
            public Model model;
            public Vector3 scale;
            public Vector3 color;
        }

        protected List<physicModel> physicModels = new List<physicModel>();
        protected List<physicModel> physicModelsToRemove = new List<physicModel>();

        protected CollisionSkin collision;

        private int dimension;

        protected static Random random = new Random();

        public Level1(Game game, int dimension)
            : base(game)
        {
            this.dimension = dimension;
            //physicModels.Add(createPhysicBox(game, new Vector3(100, 0.1f, 100), Matrix.Identity, new Vector3(0, -20.0f, -0), 1.0f, new Vector3(1, 0, 0), true));
            for (int j = 0; j < dimension; j++)
            {
                for (int i = 0; i < dimension; i++)
                {
                    physicModels.Add(createPhysicBox(game, new Vector3(4f, 4f, 4f), Matrix.Identity, new Vector3(i * 4f, j * 4f -10.0f, 0), 1f, new Vector3(random.Next(255), random.Next(255), random.Next(255)) / 255.0f, false));
                }
            }
        }

        protected physicModel createPhysicBox(Game game, Vector3 sideLengths, Matrix orientation, Vector3 position, float mass, Vector3 color, bool frozen)
        {
            float junk; Vector3 com; Matrix it, itCoM;
            var obj = new physicModel();
            obj.body = new Body();
            collision = new CollisionSkin(obj.body);
            
            collision.AddPrimitive(new Box(-0.5f * sideLengths, orientation, sideLengths), new MaterialProperties(0.8f, 0.8f, 0.7f));
            obj.body.CollisionSkin = collision;

            PrimitiveProperties primitiveProperties =
                new PrimitiveProperties(PrimitiveProperties.MassDistributionEnum.Solid, PrimitiveProperties.MassTypeEnum.Density, mass);

            collision.GetMassProperties(primitiveProperties, out junk, out com, out it, out itCoM);
            obj.body.BodyInertia = itCoM;
            obj.body.Mass = junk;

            obj.body.MoveTo(position, Matrix.Identity);
            collision.ApplyLocalTransform(new Transform(-com, Matrix.Identity));
            obj.body.EnableBody();
            obj.scale = sideLengths;
            obj.model = game.Content.Load<Model>("Models/box");
            obj.color = color;
            obj.body.Immovable = frozen;
            return obj;
        }

        Matrix[] boneTransforms = null;
        int boneCount = 0;

        public override void Update(GameTime gameTime)
        {
            foreach (physicModel a in physicModels)
            {
                if (a.body.Position.Y < -100.0f)
                {
                    a.body.DisableBody();
                    physicModelsToRemove.Add(a);
                }
            }
            foreach (physicModel a in physicModelsToRemove)
            {
                physicModels.Remove(a);
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (physicModel a in physicModels)
            {
                drawModel(a);
            }
           base.Draw(gameTime);
        }

        private void drawModel(physicModel physicsmodel)
        {

            if (boneTransforms == null || boneCount != physicsmodel.model.Bones.Count)
            {
                boneTransforms = new Matrix[physicsmodel.model.Bones.Count];
                boneCount = physicsmodel.model.Bones.Count;
            }

            physicsmodel.model.CopyAbsoluteBoneTransformsTo(boneTransforms);

            Camera camera = (Game.Services.GetService(typeof(Camera)) as Camera);

            foreach (ModelMesh mesh in physicsmodel.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    if (physicsmodel.body.CollisionSkin != null)
                        effect.World = boneTransforms[mesh.ParentBone.Index] * Matrix.CreateScale(physicsmodel.scale) * physicsmodel.body.CollisionSkin.GetPrimitiveLocal(0).Transform.Orientation * physicsmodel.body.Orientation * Matrix.CreateTranslation(physicsmodel.body.Position);
                    else
                        effect.World = boneTransforms[mesh.ParentBone.Index] * Matrix.CreateScale(physicsmodel.scale) * physicsmodel.body.Orientation * Matrix.CreateTranslation(physicsmodel.body.Position);

                    effect.View = camera.View;
                    effect.Projection = camera.Projection;
                    effect.DiffuseColor = physicsmodel.color;

                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;
                }
                mesh.Draw();
            }

        }

    }
}
